package com.hd.assistant.biz.manager.impl.share;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hd.assistant.biz.manager.exception.ManagerException;
import com.hd.assistant.biz.manager.share.ShareManager;
import com.hd.assistant.dal.dataobject.share.Share;
import com.hd.assistant.dal.dataobject.share.ShareRecord;



public class DefaultShareRedirectManager {

	private final static Logger log = LoggerFactory.getLogger(DefaultShareRedirectManager.class);
	
	private Long writeToDbInterval = 200*1000l;//轮训间隔 按毫秒算 具体的时间还要加上随机生成的一段
	
	private Long monitorLoopInterval = 30*1000l;
	
	
	/**
	 * 设置本地缓存的最大条数 当达到这个条数时 Monitor会强制触发数据迁移
	 */
	private Long maxLocalSize = 40000l;
	
	private Integer defaultTaskSize = 100;
	private Integer TASK_POOP_SIZE = 20;
	
	private ConcurrentLinkedQueue<ShareRecord> shares = null;
	
	private ThreadPoolExecutor threadPool = null;
	

	private ShareManager shareManager;
	
	public Long getWriteToDbInterval() {
		return writeToDbInterval;
	}
	public void setWriteToDbInterval(Long writeToDbInterval) {
		this.writeToDbInterval = writeToDbInterval;
	}
	public ShareManager getShareManager() {
		return shareManager;
	}
	public void setShareManager(ShareManager shareManager) {
		this.shareManager = shareManager;
	}
	public void init(){
		log.warn("Begin init DefaultClickedRedirectManager。。。。。。。。");
		//初始化监听器
		ShareDataMoveMonitor monitor = new ShareDataMoveMonitor(this);
		monitor.setWriteToDbInterval(writeToDbInterval);
		Random random = new Random();
		long interval = monitorLoopInterval+random.nextInt(30000);
		monitor.setMonitorLoopInterval(interval);
		new Thread(monitor).start();
		
		
		//初始化线程池
		threadPool = new ThreadPoolExecutor(TASK_POOP_SIZE, TASK_POOP_SIZE,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
		
		shares = new ConcurrentLinkedQueue<ShareRecord>();
	}
	public boolean autoProcess(String shareId,String refer,String ip,Date time) {
		try{
			if(shares == null)
				return false;
			Share share = this.shareManager.getShareFromCache(shareId);
			if(share == null)
				return false;
			
			ShareRecord record = new ShareRecord();
			record.setIp(ip);
			record.setTid(share.getId());
			record.setUserId(share.getUserId());
			record.setRefer(refer);
			record.setTime(time);
			return this.shares.offer(record);
		}catch(Exception e){
			return false;//外界调用此方法 必须保证不挂
		}
	}

	/**
	 * 未考虑机子down了数据的丢失问题
	 */
	public boolean dumpToDB() {
		// 获取到需要迁移的数据
		
		ConcurrentLinkedQueue<ShareRecord> newData = new ConcurrentLinkedQueue<ShareRecord>(); 
		ConcurrentLinkedQueue<ShareRecord> oldData = shares;
		//切换
		shares = newData;
		
		int totalSize = oldData.size();
		int taskSize = totalSize/defaultTaskSize;
		if((totalSize % defaultTaskSize) != 0)
			taskSize = taskSize + 1;
		
		List<ShareRecord> totalItems = new ArrayList<ShareRecord>(oldData);
		
		oldData = null;
		// 分发到线程池
		for(int i=0 ; i<taskSize ;i++){
			int start = i*defaultTaskSize;
			int end = (i+1)*defaultTaskSize > totalItems.size() ? totalItems.size() :(i+1)*defaultTaskSize;
			if(start > totalItems.size()  || end > totalItems.size())
				break;
			
			List<ShareRecord> items = new ArrayList<ShareRecord>(totalItems.subList(start, end));
			MoveToDBTask task = new MoveToDBTask(items);
			this.threadPool.execute(task);
		}
		
		
		return true;
	}
	public boolean needToMove(){
		return this.shares.size() >= maxLocalSize;
	}
	
	protected void convertToDb(ShareRecord item) {	
		//插入记录到db
		try {
			shareManager.insertShareRecordToDB(item);
		} catch (ManagerException e) {
			log.error("MoveToDBTask  convertToDb - insertShareRecordToDB",e);
		}
	}
	
	class MoveToDBTask implements Runnable{

		List<ShareRecord> items;
		public MoveToDBTask(List<ShareRecord> items) {
			super();
			this.items = items;
		}
		public void run() {
			
			for(ShareRecord item : items){
				convertToDb(item);
			}
		}
		
		
	}

	
}
